package cc.owoo.godpen.network.http;

import cc.owoo.godpen.util.Path;

import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;

/**
 * 抽象的请求信息
 * Created by nimensei
 * 2022-02-27 上午 01:58
 **/
public class AbstractRequest extends AbstractHost implements MessageWrite {
    final Path path = new Path();// 请求路径
    final HashMap<String, String> params = new HashMap<>();// 请求URL参数
    String method = "GET";// 请求方式
    String version;// 协议版本号

    @Override
    public void initialize() {
        super.initialize();
        method = "GET";
        path.clear();
        params.clear();
    }

    @Override
    public void write(OutputStream output) throws IOException {
        HttpAnalysis.write(output, this, this);
    }

    @Override
    public String stringifyAgreement() {
        return getMethod() + ' ' +
                getUrl(false, false, true, true) + ' ' +
                getVersion();
    }

    /**
     * 拷贝对象
     *
     * @param abstractRequest 拷贝源
     */
    public void copySetRequest(AbstractRequest abstractRequest) {
        method = abstractRequest.method;
        path.clear();
        path.appendLast(abstractRequest.path);
        params.clear();
        params.putAll(abstractRequest.params);
    }

    /**
     * 序列化URL
     *
     * @return URL地址
     */
    String getUrl() {
        return getUrl(true, true, true, true);
    }

    /**
     * 序列化URL
     *
     * @param isAgreement 是否拼接协议头
     * @param isHost      是否拼接地址
     * @param isPath      是否拼接路径
     * @param isParams    是否拼接参数
     * @return URL地址
     */
    String getUrl(boolean isAgreement, boolean isHost, boolean isPath, boolean isParams) {
        StringBuilder string = new StringBuilder();
        String agreement = this.agreement == null ? "http" : this.agreement;
        if (isAgreement)
            string.append(agreement).append("://");
        con:
        if (isHost) {
            if (host == null) {
                string.append("localhost");
                break con;
            }
            string.append(host.getHostName());
            if (port == -1)
                break con;
            if ((agreement.equals("http") && port != 80) || (agreement.equals("https") && port != 443))
                string.append(':').append(port);
        }
        if (isPath)
            string.append(path.stringify());
        if (isParams && params.size() > 0) {
            if (string.length() > 0)
                string.append('?');
            string.append(HttpUtil.paramsToUrl(params));
        }
        return string.toString();
    }

    /**
     * 解析URL
     *
     * @param url URL地址
     */
    void setUrl(String url) {
        if (url == null)
            return;
        url = analysisHost(url).trim();
        int index = url.indexOf('?');
        if (index != -1) {
            analysisParams(url.substring(index + 1));
            url = url.substring(0, index);
        }
        setPath(url);
    }

    /**
     * 获取协议版本号
     *
     * @return 协议版本号
     */
    String getVersion() {
        return version == null ? "HTTP/1.1" : version;
    }

    /**
     * 设置协议版本号
     *
     * @param version 协议版本号
     */
    void setVersion(String version) {
        this.version = version;
    }

    /**
     * 设置请求方法，一般为GET、POST等
     *
     * @return 请求方法
     */
    String getMethod() {
        return method;
    }

    /**
     * 判断请求方法是否相等
     *
     * @param method 需要比对的字符串
     * @return 是否相等
     */
    boolean isMethod(String method) {
        if (this.method == null)
            return method == null;
        return this.method.equalsIgnoreCase(method);
    }

    /**
     * 设置请求方法，一般为GET、POST等
     *
     * @param method 请求方法
     */
    void setMethod(String method) {
        this.method = method == null ? "GET" : method.toUpperCase();
    }

    /**
     * 获取请求路径
     *
     * @return 请求路径
     */
    public Path getPath() {
        return path;
    }

    /**
     * 设置请求路径
     *
     * @param path 请求路径
     */
    void setPath(String path) {
        this.path.set(path);
    }

    /**
     * 设置请求路径
     *
     * @param path 请求路径
     */
    void setPath(Path path) {
        this.path.set(path);
    }

    /**
     * 解析URL参数
     *
     * @param str 字符串
     */
    private void analysisParams(String str) {
        for (String s : str.split("&")) {
            int index = s.indexOf("=");
            if (index == -1)
                continue;
            String key = s.substring(0, index);
            String value = s.substring(index + 1);
            params.put(key, value);
        }
    }

    /**
     * 获取请求URL参数
     *
     * @param key 键
     * @return 值
     */
    public String getParam(String key) {
        return params.get(key);
    }

    /**
     * 设置请求URL参数
     *
     * @param key   键
     * @param value 值
     * @return 如果该键已被设置过，则返回被替换之前的值
     */
    String setParam(String key, String value) {
        return params.put(key, value);
    }

    @Override
    public String toString() {
        StringBuilder string = new StringBuilder();
        string.append("[agreement header]").append('\n');
        string.append("agreement:").append(agreement).append('\n');
        string.append("method:").append(method).append('\n');
        string.append("host:").append(host == null ? null : host.getHostName()).append('\n');
        string.append("port:").append(getPort()).append('\n');
        string.append("path:").append(path).append('\n');
        string.append("params:").append(params).append('\n');
        string.append("[request header]").append('\n');
        stringifyHeader(string);
        string.append("[data]").append('\n');
        HttpUtil.stringifyContent(string, content, this);
        return string.toString();
    }
}
